#include "LKH.h"

typedef struct edge {
  int to, cost;
  struct edge* next;
} edge;

typedef struct node {
  edge* first_edge;
} node;

int ReadEdges(int MaxCandidates) {
  FILE* EdgeFile = 0;
  Node *From, *To;
  int Dimension, Edges, i, f, d, Count = 0, from, to, cost;
  int concorde_edge_format = 0;
  node* node_set;
  edge *e, *e_next;
  char line[81];

  if (EdgeFiles == 0) return 0;
  Dimension = ProblemType != ATSP ? DimensionSaved : 2 * DimensionSaved;
  node_set = (node*)calloc(Dimension + 1, sizeof(node));
  for (f = 0; f < EdgeFiles; f++) {
    if (!(EdgeFile = fopen(EdgeFileName[f], "r")))
      eprintf("Cannot open EDGE_FILE: \"%s\"", EdgeFileName[f]);
    if (TraceLevel >= 1) printff("Reading EDGE_FILE: \"%s\" ... ", EdgeFileName[f]);
    fscanf(EdgeFile, "%d %d\n", &i, &Edges);
    if (i != Dimension) eprintf("EDGE_FILE \"%s\" does not match problem", EdgeFileName[f]);
    for (i = 0; i < Edges; i++) {
      fgets(line, 80, EdgeFile);
      Count = sscanf(line, "%d %d %d\n", &from, &to, &cost);
      if (i == 0) concorde_edge_format = Count == 3;
      if (concorde_edge_format ? Count != 3 : Count != 2)
        eprintf("EDGE_FILE \"%s\": Wrong format\n%s", EdgeFileName[f], line);
      from++;
      assert(from >= 1 && from <= Dimension);
      to++;
      assert(to >= 1 && to <= Dimension);
      e = (edge*)malloc(sizeof(edge));
      e->to = to;
      e->next = node_set[from].first_edge;
      e->cost = cost;
      node_set[from].first_edge = e;
    }
    for (from = 1; from <= Dimension; from++) {
      From = &NodeSet[from];
      for (e = node_set[from].first_edge; e; e = e->next) {
        To = &NodeSet[e->to];
        d = concorde_edge_format ? e->cost * Precision + From->Pi + To->Pi : D(From, To);
        AddCandidate(From, To, d, 1);
        AddCandidate(To, From, d, 1);
      }
      for (e = node_set[from].first_edge; e; e = e_next) {
        e_next = e->next;
        free(e);
      }
    }
    fclose(EdgeFile);
    if (TraceLevel >= 1) printff("done\n");
    for (from = 1; from <= Dimension; from++) node_set[from].first_edge = 0;
  }
  free(node_set);
  ResetCandidateSet();
  if (MaxCandidates > 0) TrimCandidateSet(MaxCandidates);
  return 1;
}
